package com.gxa.hualianeshop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.gxa.hualianeshop.common.base.RedisKeys;
import com.gxa.hualianeshop.common.util.MD5Util;
import com.gxa.hualianeshop.entity.pojo.Empl;
import com.gxa.hualianeshop.entity.vo.EmplVO;
import com.gxa.hualianeshop.mapper.EmplMapper;
import com.gxa.hualianeshop.service.EmplService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author gxa
 * @since 2023-07-05
 */
@Slf4j
@Service
@Transactional
public class EmplServiceImpl extends ServiceImpl<EmplMapper, Empl> implements EmplService {

    @SuppressWarnings("all")
    @Autowired
    EmplMapper emplMapper;

    @Autowired
    RedisTemplate<String,Object> redisTemplate;

    @Override
    public Empl login(String phone, String pwd) {

        // 声明一个局部的lambda类型的查询包装器
        LambdaQueryWrapper<Empl> lambdaQuery = Wrappers.lambdaQuery(Empl.class);
        lambdaQuery.eq(Empl::getEmplPhone,phone).eq(Empl::getEmplPwd, MD5Util.encode(pwd));
        Empl one = this.getOne(lambdaQuery);
        return one;
    }

    @Override
    public EmplVO getEmplRoleMenuInfo(Integer id) {

        //通过缓存来优化访问
        //1. 通过用户id/phone 去redis中判断是否存在
        // key: perms:1
        Boolean hasKey = redisTemplate.hasKey(RedisKeys.PERMS_KEY + id);

        // 绑定目标key
        BoundValueOperations<String, Object> boundValueOps = redisTemplate.boundValueOps(RedisKeys.PERMS_KEY + id);

        // 如果key存在
        if(hasKey!=null && hasKey){
            Object o = boundValueOps.get();
            log.info("o:"+o);

            // 如果读取权限信息完成,就把EmplVO 直接返回
            return (EmplVO)o;
        }
        EmplVO emplVO = emplMapper.getEmplRoleMenuInfo(id);
        // 再写入缓存,缓存自身有一个和数据库一致性的问题,如果通过过期时间,能最大限度防止一定时间的脏读
        // 问题的可能性: 数据库中的权限修改成功,但缓存未能同步更新(直接删除缓存)
        boundValueOps.set(emplVO,15, TimeUnit.MINUTES);



        return emplVO;
    }

    @Override
    public Boolean modifyRoles(Integer id, Integer[] roleIds) {

        // 当用户修改角色信息时, 也需要同时处理权限缓存

        // 缓存和数据库的同步问题:

        // 1. 先删除缓存, 再修改数据库:  缓存中不存在,先读取了数据库先于修改完成
        // 2. 先修改数据库, 再删除缓存:  会导致在修改未完成的情况下产生脏读
        //3. 先删除缓存->修改数据库-> 删除缓存: 缓存双删策略
        //4. 利用消息队列实现双写一致: 高并发+签收机制

        // 删除缓存
        redisTemplate.delete(RedisKeys.PERMS_KEY + id);

        // TODO 修改用户的角色信息

        // 删除缓存
        redisTemplate.delete(RedisKeys.PERMS_KEY + id);

        return null;
    }
}
